<template>
	<view class="cloud-image">
		<view class="cloud-image__content">
			<block v-if="imageNumber==1">
				<view class="flex justify-between">
					<text class="text-black">{{title}}</text>
					<text class="text-sm margin-left-sm text-gray">{{tips}}</text>
				</view>
				<view class="one-img-box">
					<image v-if="val" :src="val" mode="aspectFit" class="image" :style="imageSizeStyle"
						@click="upload(0)"></image>
					<view class="right-btn-box">
						<uni-icons type="eye-filled" size="25" color="#777777" v-if="val" @click="previewImage_2(val)"></uni-icons>
						<!-- <view class="pre-btn-box" v-if="val" @click="previewImage_2(val)">
							<text>看大图</text>
						</view> -->
						<uni-icons v-if="isShowIcon" class="content-image-icon" :type="suffixIcon" :size="iconSize"
							color="#c0c4cc" @click="upload()"></uni-icons>
						<uni-icons v-else-if="!disabled" class="image-delete" type="trash" size="20" color="#ff0000"
							@click="del(0)">
						</uni-icons>
					</view>

				</view>
			</block>
			<block v-else>
				<view class="">
					<wjf-drag-image v-model="toDragImage" :delImage="delDragImage" :updateImage="updateDragImage" @addImage="dragAddImg" :cols="lineCols"></wjf-drag-image>
				</view>

			</block>
		</view>
	</view>
</template>

<script>
	/**
	 * 云上商城图片上传组件
	 * 重新修改后，已对原组件做了较大改动，上传1张图片时做了预览处理加入了预览接口 
	 * 上传多张图片时，又引入拖动图片组件，以便可以对图片进行排序处理
	 * @alias https://ext.dcloud.net.cn/plugin?id=3647
	 * @property {String} name  上传文件前缀
	 * @property {String} title  提示标题
	 * @property {String} tips  提示说明
	 * @property {String,Array} modelValue 变量，可以是字符串或者数组
	 * @property {String} suffixIcon  默认图标
	 * @property {Number} imageNumber  上传文件数量，默认1
	 * @property {String} size  文件显示尺寸，宽x高，例如：300x200
	 * @property {Boolean} isHold  是否可用一直上传
	 * 定义res-images事件,前端使用@res-images接收成功上传的图片文件
	 * this.$emit('res-images')
	 *
	 */

	// 生成随机字符串
	function generateRandomString(length = 6) {
		const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
		let randomString = '';
		for (let i = 0; i < length; i++) {
			const randomIndex = Math.floor(Math.random() * chars.length);
			randomString += chars.charAt(randomIndex);
		}
		return randomString;
	}
	// 辅助函数：获取文件名后缀
	function getFileSuffix(file, accept = 'image') {
		const regex = /\.[^.]+$/;
		if (file.name) {
			return file.name.split('.').pop().toLowerCase();
		} else if (regex.test(file.url)) {
			return file.url.split('.').pop().toLowerCase();
		} else {
			console.warn('文件对象缺少必要属性，无法提取文件后缀，设置默认后缀');
			let fix = 'png';
			switch (accept) {
				case 'image':
					fix = 'png';
					break;
				case 'video':
					fix = 'mp4';
					break;
				default:
					break;
			}
			return fix;
		}
	}
	// Nano ID 调用， 生成唯一加密文件名 因Nano在微信小程序中不能用而放弃
	function nanoid(size = 21) {
	  const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-';
	  let id = '';
	  for (let i = 0; i < size; i++) {
	    id += alphabet[Math.floor(Math.random() * alphabet.length)];
	  }
	  return id;
	}

	export default {
		name: 'cloud-image-alioss',
		data() {
			return {
				val: "",
				srcList: [],
				draggingIndex: null,
			};
		},
		props: {
			// 文件名前缀
			prefix: {
				type: String,
				default: ''
			},
			// 是否使用原文件名
			isSameName: {
				type: Boolean,
				default: false
			},
			title: {
				type: String,
				default: ''
			},
			tips: {
				type: [String, Number],
				default: ''
			},
			modelValue: [Number, String, Array],
			suffixIcon: {
				type: String,
				default: 'plusempty'
			},
			imageNumber: {
				type: [Number, String],
				default: 1
			},
			/**
			 * 图片大小，超出将对其进行压缩 默认200k 200*1024
			 * 父组件设置此属性值时，是以k为单位的200即代表200k
			 */
			imageMaxSize: {
				type: [Number, String],
				default: 200
			},
			/**
			 *  每行图片数量
			 * 当图片大于1时，控制每行列数的同时也控制了图片的大小
			 * 因此，每次调用时应尽可能配置此值
			 * 使用表单输入时，图片要尽量大一些，否则容易误删除和不容易移动
			 */
			lineCols: {
				type: [Number, String],
				default: 3
			},
			size: {
				type: String,
				default: ''
			},
			iconSize: {
				type: [String, Number],
				default: 50
			},
			isHold: {
				type: Boolean,
				default: false
			},
			disabled: {
				type: Boolean,
				default: false
			},
			/**
			 * 上传到oss的路径
			 * 父组件设置该属性时，须注意要写全路径
			 */
			uploadDir: {
				type: String,
				default: 'upload-file'
			},
		},
		watch: {
			modelValue(newVal) {
				if (typeof newVal == "object" && newVal) {
					this.srcList = newVal
				} else {
					this.val = newVal
				}
				if (this.formItem) {
					this.formItem.setValue(newVal)
				}
			}
		},
		computed: {
			isShowIcon() {
				if (this.disabled) {
					return false;
				}
				if (!this.suffixIcon) {
					return false;
				}
				if (this.isHold) {
					return true;
				}
				if (this.imageNumber*1 > 1) {
					return (this.imageNumber * 1) - this.srcList.length > 0;
				}
				return !this.val;
			},
			imageSizeStyle() {
				if (this.size) {
					let strarr = this.size.split("x");
					if (strarr.length == 1) {
						strarr.push(strarr[0]);
					}
					return `width:${strarr[0]}rpx;height:${strarr[1]}rpx;`
				}
				return ""
			},
			// 向子组件传递当前值
			toDragImage() {
				return this.modelValue
			}
		},
		created() {
			console.log(typeof this.modelValue, this.modelValue)
			if (typeof this.modelValue == "object" && this.modelValue) {
				this.srcList = this.modelValue
			} else {
				this.val = this.modelValue
			}
			//this.val = this.value
			this.form = this.getForm('uniForms')
			this.formItem = this.getForm('uniFormsItem')
			if (this.formItem) {
				if (this.formItem.name) {
					this.rename = this.formItem.name
					this.form.inputChildrens.push(this)
				}
			}
		},
		methods: {
			/**
			 * 初始化变量值
			 */
			init() {

			},
			/**
			 * 获取父元素实例
			 */
			getForm(name = 'uniForms') {
				let parent = this.$parent;
				let parentName = parent.$options.name;
				while (parentName !== name) {
					parent = parent.$parent;
					if (!parent) return false;
					parentName = parent.$options.name;
				}
				console.log('父组件', parent);
				return parent;
			},
			uploadCallback(srcs) {
				if (this.imageNumber == 1) {
					this.val = srcs[0]
					this.$emit('update:modelValue', this.val);
					this.$emit('res-images',this.val)
				} else {
					this.srcList = this.srcList.concat(srcs)
					this.$emit('update:modelValue', this.srcList);
					this.$emit('res-images',this.srcList)
				}

			},
			// 
			del(index) {
				console.log(index);
				if (this.imageNumber == 1) {
					this.val = ""
					this.$emit('update:modelValue', this.val);
				} else {
					this.srcList.splice(index, 1)
					this.$emit('update:modelValue', this.srcList);
					console.log(this.modelValue);
				}
			},
			/**
			 * 向子组件传递这个函数时，必须加冒号，否则传递的是字符串
			 * 接收子组件删除图片后的图片数组并同步到父组件
			 * @param {Object} index
			 */
			delDragImage(index){
				this.srcList.splice(index, 1)
				this.$emit('update:modelValue', this.srcList);
				// console.log(this.modelValue);
			},
			updateDragImage(imgArr){
				// setTimeout(()=>{
				// 	this.$emit('update:modelValue', imgArr);
				// },3000)
				this.$emit('update:modelValue', imgArr);
			},
			previewImage(index) {
				uni.previewImage({
					current: index,
					urls: this.srcList
				});
			},
			previewImage_2(val) {
				console.log(val);
				uni.previewImage({
					current: 0,
					urls: [val]
				});
			},
			dragAddImg(){
				console.log('收到dragAddImg');
				this.upload()
			},
			upload() {
				if (this.disabled) {
					this.previewImage(0)
					return false;
				}
				let dt = new Date();
				uni.chooseImage({
					count: this.imageNumber - this.srcList.length,
					success: async (res) => {
						let paths = [];
						let imgSize = res.tempFiles[0].size
						// console.log(imgSize)
						// this.uploadCallback(res.tempFilePaths);
						let promises = [];
						uni.showLoading({
							title: "图片上传中"
						})
						//生成阿里云oss签名
						let resOss = await this.getAliyunOssSignature()
						// console.log('OSS签名', resOss);
						this.toCompressImage(res.tempFiles, resOss)
					}
				});
			},
			toCompressImage(tempFiles, resOss) {
				let comPromise = []
				tempFiles.map(file => {
					// #ifdef H5
					comPromise.push(this.compressImage(file.path))
					// #endif
			
					// #ifndef H5
					comPromise.push(this.compressImg(file.path))
					// #endif
				})
				Promise.all(comPromise).then(res => {
					// console.log(res);
					uni.hideLoading()
					this.toUploadImg(res, resOss)
				})
			},
			//上传整理(压缩)过和文件 包括重置文件名等操作
			toUploadImg(ttRes, resOss) {
				//循环上传
				// res.tempFilePaths
				let promises = []
				ttRes.map((filePath, index) => {
			
					let suffix = 'png'; //统一图片后缀
			
					// 生成唯一ID
					const uniqueId = nanoid();
					// 生成唯一文件名
					let fileAllName = `${uniqueId}.${suffix}`;
			
					let ossPath = `${this.uploadDir}/${this.prefix}${fileAllName}`;
					let uploadPromise = uploadFile(filePath, ossPath, index, resOss);
					promises.push(uploadPromise)
				})
			
				Promise.all(promises).then(res => {
					// console.log('Promise.all结果', res);
					uni.hideLoading();
					this.uploadCallback(res);
				});
			
				function uploadFile(filePath, ossPath, index, ossSignature) {
					uni.showLoading({
						title: '正在上传图片...',
						mask: false
					});
					return new Promise((resolve, reject) => {
						let formDataPara = {
							'key': ossPath,
							'policy': ossSignature.policy,
							'OSSAccessKeyId': ossSignature.accessKeyId,
							'signature': ossSignature.signature,
							'success_action_status': '200',
							// 'callback': ossSignature.callback  //不使用此参数，似乎上传速度更快一些
						}
						// console.log(formDataPara, filePath, );
						let result = uni.uploadFile({
							url: ossSignature.hostUrl, //OSS地址，https
							filePath: filePath,
							name: 'file',
							formData: formDataPara,
							onUploadProgress: pro => {},
							success: res => {
								// console.log("uploadFile", res)
								uni.hideLoading()
								resolve(ossSignature.hostUrl + '/' + ossPath)
								// if (res.fileID.indexOf("cloud://") != -1) {
								// 	//用这个转换一下，有一个隐藏的好处，可以等待文件发布到cdn，避免立即访问不到
								// 	uniCloud.getTempFileURL({
								// 		fileList: [res.fileID]
								// 	}).then(res2 => {
								// 		resolve(res2.fileList[0].tempFileURL);
								// 	})
								// } else {
								// 	//延时返回，可以等待文件发布到cdn，避免立即访问不到
								// 	setTimeout(() => {
								// 		resolve(res.fileID);
								// 	}, 200);
								// }
							},
							fail: () => {
								reject(false);
							}
						});
					});
				};
			},
			// 非H5的图片压缩
			async compressImg(imagePath) {
				uni.showLoading({
					title: '正在处理图片...',
					mask: false
				});
				return new Promise((resolve) => {
					// 目标大小（字节），1M = 1024 * 1024 字节
					const targetSize = this.imageMaxSize * 1024;
					let quality = 100;
			
					function compress(imagePath, quality) {
						uni.compressImage({
							src: imagePath,
							quality: quality,
							success: (res) => {
								uni.getFileInfo({
									filePath: res.tempFilePath,
									success: (info) => {
										if (info.size <= targetSize || quality <= 10) {
											// 如果文件小于等于目标大小或质量已降至最低，返回结果
											resolve(res.tempFilePath);
										} else {
											// 继续压缩
											compress(imagePath, quality - 10);
										}
									}
								});
							},
							fail: (err) => {
								console.error('压缩失败', err);
							}
						});
					}
			
					compress(imagePath, quality);
				})
			},
			// H5的压缩图片
			async compressImage(src) {
				uni.showLoading({
					title: '正在处理图片...',
					mask: false
				});
				return new Promise((resolve) => {
					const img = new Image();
					img.src = src;
					img.onload = () => {
						let canvas = document.createElement('canvas');
						const ctx = canvas.getContext('2d');
						const maxSize = this.imageMaxSize * 1024; // 参数以k为单位，1k=1024字节
						let quality = 1;
						// console.log(this.imageMaxSize);
			
						const compress = () => {
							canvas.width = img.width;
							canvas.height = img.height;
							ctx.clearRect(0, 0, canvas.width, canvas.height);
							ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
							let base64Data = canvas.toDataURL('image/jpeg', quality);
							const compressedSize = Math.round((base64Data.length * 3) / 4);
			
							if (compressedSize > maxSize && quality > 0.1) {
								quality -= 0.1;
								compress();
							} else {
								// console.log(`Final size: ${(compressedSize / 1024).toFixed(2)} KB`);
								uni.hideLoading()
								resolve(base64Data);
							}
						};
						compress();
					};
				});
			},
			// 获取阿里云签名
			async getAliyunOssSignature() {
				const objWjf = uniCloud.importObject('wjf-co', {
					loadingOptions: { // loading相关配置
						title: '正在处理图片数据...', // 显示的loading内的提示文字。默认值为：加载中...
						mask: true // 是否使用透明遮罩，配置为true时不可点击页面其他内容。默认值为：true
					}
				})
				return await objWjf.aliOssSignature()
			}
		}
	}
</script>

<style lang="scss">
	.one-img-box {
		display: flex;

		.right-btn-box {
			display: flex;
			flex-direction: column;
			justify-content: space-between;
			align-items: flex-start;
			margin-left: 10rpx;
			padding: 20rpx 0;

			.pre-btn-box {
				padding: 10rpx 20rpx;
				background-color: #eee;
				border-radius: 10rpx;
				border: 1px solid #aaa;
				cursor: pointer;

				text {
					color: #555;
				}
			}
		}
	}

	.cloud-image {
		width: 100%;
		overflow: auto;
	}

	.image {
		width: 200rpx;
		height: 200rpx;
		border-radius: 10rpx;
	}

	.scroll-view_H {
		white-space: nowrap;
		flex-wrap: wrap;
		width: 100%;
	}

	.scroll-view-item_H {
		display: inline-block;
		width: 200rpx;
		height: 200rpx;
		text-align: center;
		margin-right: 16rpx;
		position: relative;
		border: 1upx solid #ececec;
		border-radius: 10rpx;
		margin-bottom: 12rpx;

		.image-delete {
			position: absolute;
			right: 0rpx;
			top: 0rpx;
			line-height: 1;
			padding: 10rpx;
			background: #fff;
			border-radius: 0 10rpx 0 10px;
		}
	}

	.wrap-imgs {
		display: flex;
		flex-wrap: wrap;
	}

	.content-image-icon {
		line-height: 200rpx;
	}

	.scroll-view_H2 {
		display: flex;
		align-items: center;
	}

	.result {
		text-align: right;
	}

	.text-gray {
		color: #b4b4b4;
	}
</style>